﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RATSharp.Rest;
using RATSharp.Model;
using System.Threading.Tasks;
using RATSharp.Collection;
using RATSharp.Cal;
using RATSharp.Property;
using RATSharp.Validator;
namespace RATSharp
{
    delegate void MenuHandler();
    delegate void ObjectHandler(RATSharp.Model.Object obj);
    class Menu
    {
        public static User LoggedUser;

        private RestService service;
        bool authorized;
        Properties properties;

        public Menu()
        {
            authorized = false;
            properties = PropertyLoader.resolve();
            PropertyLoader.PropertiesChangeEvent += handlePropertiesChanged;
        }

        private Reservations reservationsContext { get; set; }

        public void start()
        {
            while (true)
            {
                if (!authorized)
                {
                    authorized = authorize();
                }

                MenuList<MenuItem<string, MenuHandler>, MenuItem<string, MenuHandler>> menuList = new MenuList<MenuItem<string, MenuHandler>, MenuItem<string, MenuHandler>>("Main Menu");
                if (authorized)
                {
                    menuList.Add(new MenuItem<string, MenuHandler>("Personal Calendar", new MenuHandler(handlePersonalCalendar)));
                    menuList.Add(new MenuItem<string, MenuHandler>("Favourites", new MenuHandler(handleFavourites)));
                    menuList.Add(new MenuItem<string, MenuHandler>("Pick Up", new MenuHandler(handlePickUpAction)));
                    menuList.Add(new MenuItem<string, MenuHandler>("Return it back", delegate() { ReturnItBackAction act = new ReturnItBackAction(service); act.returnItBack(); }));
                    menuList.Add(new MenuItem<string, MenuHandler>("Browse Objects", new MenuHandler(handleBrowseObject)));
                }
                menuList.Add(new MenuItem<string, MenuHandler>("Preferences", new MenuHandler(handlePreferences)));
                menuList.Add(new MenuItem<string, MenuHandler>("Exit", delegate() { Environment.Exit(0); }));
                Console.Write(menuList);
                menuList.ElementAt(MenuUtilities.GetSimpleInput(new IntRangeInputValidator(1, menuList.Count)) - 1).menuHandler();
            }


        }

        private bool authorize()
        {
            if (properties == null)
            {
                Console.WriteLine("Connection settings cannot be evaluated! Check your Preferences!");
                return false;
            }
            service = new RestService(properties);
            service.init();
            Console.WriteLine("Logging in...");

            User user;

            if (!MenuUtilities.WaitForCommTask(service.getUserAsync(properties.username), out user))
            {
                Console.WriteLine("Login failed. Is server alive? Check your settings!");
                return false;
            }
            else
            {
                Console.WriteLine("You are logged as " + user.Name);
                LoggedUser = user;
                return true;
            }

        }

        private void handlePreferences()
        {
            PropertiesBrowser propBrowser  = new PropertiesBrowser(properties);
            propBrowser.init();
        }

        private void handlePickUpAction()
        {
            ObjectBrowser browser = new ObjectBrowser(service);
            RATSharp.Model.Object obj =  browser.init();
            if (obj == null)
            {
                return;
            }

           PickUpAction.pickUpAction(obj, service);
        }

        private void unimplemented()
        {
            Console.WriteLine("unimplemented");
        }


        private void handleFavourites()
        {
            bool stepback = false;
            while (!stepback)
            {
                Objects foundedObjects;
                if (!MenuUtilities.WaitForCommTask(service.getFavouritesAsync(), out foundedObjects))
                {
                    return;
                }

                if (foundedObjects.Count == 0)
                {
                    Console.WriteLine("No favourites has been found.");
                    return;
                }


                MenuList<MenuItem<RATSharp.Model.Object, ObjectHandler>, MenuItem<string, MenuHandler>> menuList =
                    new MenuList<MenuItem<RATSharp.Model.Object, ObjectHandler>, MenuItem<string, MenuHandler>>("Favourites");
                foreach (RATSharp.Model.Object obj in foundedObjects)
                {
                    menuList.Add(new MenuItem<RATSharp.Model.Object, ObjectHandler>(obj, handleFavourite));
                }
                menuList.AddAdditional(new MenuItem<string, MenuHandler>("Step Back", delegate() { stepback = true; }));
                Console.Write(menuList);
                int choice = MenuUtilities.GetSimpleInput(new IntRangeInputValidator(1, menuList.fullCount)) - 1;

                if (choice < menuList.Count)
                {
                    menuList.ElementAt(choice).menuHandler(menuList.ElementAt(choice).value);
                }
                else
                {
                    menuList.GetAdditional(choice).menuHandler();
                }
            }
        }



        private void handleFavourite(RATSharp.Model.Object fav)
        {
            ObjectViewer viewer = new ObjectViewer(service, fav);
            viewer.init();
        }

        private void handleBrowseObject()
        {
            ObjectBrowser browser = new ObjectBrowser(service);
            RATSharp.Model.Object obj = browser.init();

            if (obj != null)
            {
                ObjectViewer viewer = new ObjectViewer(service, obj);
                viewer.init();
            }
        }


        public void handlePersonalCalendar()
        {
            Console.WriteLine("What year?");
            int year = MenuUtilities.GetSimpleInput(new IntRangeInputValidator(1970, 2500));
            Console.WriteLine("What month?");
            int month = MenuUtilities.GetSimpleInput(new IntRangeInputValidator(1, 12));
   
            AbstractCalendarDataProvider dataProvider = new CalendarUserDataProvider(service, month, year);
            Calendar calendar = new Calendar(year, month, dataProvider);
            calendar.reservationHandler = new PersonalReservationHandler(service, dataProvider.invalidate);

            calendar.init();
        }

        private void handlePropertiesChanged(object source, Properties properties)
        {
            authorized = false;
            this.properties = properties;
        }

    }
}